import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from yellowbrick.cluster import KElbowVisualizer
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import AgglomerativeClustering
from matplotlib.colors import ListedColormap
from sklearn import metrics

# 读取csv文件，以制表符分隔
df = pd.read_csv('marketing_campaign.csv', sep="\t")
# 删除缺失值
df.dropna(inplace=True)
# 将年份出生转换为年龄
df["Year_Birth"] = 2021 - df["Year_Birth"]
# 计算消费总和
df["Spent"] = df["MntWines"] + df["MntFruits"] + df["MntMeatProducts"] + df["MntFishProducts"] + df[
    "MntSweetProducts"] + df["MntGoldProds"]
# 重命名年龄列
df.rename(columns={'Year_Birth': 'Age'}, inplace=True)
# 将年份出生列重命名为年龄
y = df.drop(['Education', 'Marital_Status', 'Dt_Customer'], axis=1)

# 删除教育、婚姻状态和客户注册日期列
del_cols = ['AcceptedCmp3', 'AcceptedCmp4', 'AcceptedCmp5', 'AcceptedCmp1', 'AcceptedCmp2', 'Complain', 'Response']
ds = df.drop(del_cols, axis=1)

# 删除接受Cmp3-5列和投诉列
ds = pd.get_dummies(ds)
# 将ds中的分类变量转换为虚拟变量
scaler = StandardScaler()
scaler.fit(ds)
# 标准化数据
scaled_features = pd.DataFrame(scaler.transform(ds), columns=ds.columns)
# 主成分分析（PCA）是一种用于降低此类数据集的维度的技术，增加了可解释性，但同时最大限度地减少了信息损失。
# 将数据转换为3维
pca = PCA(n_components=3)
pca.fit(scaled_features)
# 使用PCA对数据进行降维
PCA_df = pd.DataFrame(pca.transform(scaled_features), columns=(["Education", "Income", "Kidhome"]))
# 将降维后的数据转换为DataFrame

print(scaled_features)
# 创建一个PCA模型，降维到3维
pca = PCA(n_components=3)
# 使用训练集训练模型
pca.fit(scaled_features)
# 将训练集降维到3维，并存储到PCA_df中
PCA_df = pd.DataFrame(pca.transform(scaled_features), columns=(["Education", "Income", "Kidhome"]))

print(scaled_features)

# 创建3个变量，分别存储降维后的x，y，z坐标
x = PCA_df["Education"]
y = PCA_df["Income"]
z = PCA_df["Kidhome"]

# 创建一个3D图，并存储到fig中
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection="3d")
# 在3D图中绘制降维后的数据
ax.scatter(x, y, z, c="magenta", marker="o")
# 设置图的标题
ax.set_title("A 3D Projection Of Data In The Reduced Dimension")
# 显示图
plt.savefig("3D_Projection_Of_Data_In_The_Reduced_Dimension.png")
plt.show()

# 创建一个KMeans模型
model = KMeans()
# 创建一个KElbowVisualizer模型，并设置k值为10
visualizer = KElbowVisualizer(model, k=10)
# 使用训练集训练模型
visualizer.fit(PCA_df)
# 显示模型
visualizer.show()

# 定义一个函数，用于绘制聚类结果
AC = AgglomerativeClustering(n_clusters=4)

# 使用AC对PCA_df进行聚类
AC_df = AC.fit_predict(PCA_df)
PCA_df["Clusters"] = AC_df

# 将聚类结果添加到df中
df["Clusters"] = AC_df
# 使用轮廓系数评估聚类质量
silhouette_score = metrics.silhouette_score(PCA_df, df["Clusters"])
print("Silhouette Score:", silhouette_score)

# 使用Calinski-Harabasz指数评估聚类质量
ch_score = metrics.calinski_harabasz_score(PCA_df, df["Clusters"])
print("Calinski-Harabasz Score:", ch_score)
# 绘制聚类结果
fig = plt.figure(figsize=(10, 8))
ax = plt.subplot(111, projection='3d', label="bla")
ax.scatter(x, y, z, s=40, c=PCA_df["Clusters"], marker='o', cmap='viridis')
ax.set_title("The Plot Of The Clusters")
plt.savefig("Clusters.png")
plt.show()


# 绘制柱状图，显示每个集群的数量
pl = sns.countplot(x=df["Clusters"])
# 设置图表标题
pl.set_title("Distribution Of The Clusters")
# 显示图表
plt.savefig("Clusters.png")
plt.show()

# 绘制散点图，显示每个集群的 income 和 spending 特征
pl = sns.scatterplot(data=df, x=df["Spent"], y=df["Income"], hue=df["Clusters"])
# 设置图表标题
pl.set_title("Cluster's Profile Based On Income And Spending")
# 显示图例
plt.legend()
# 显示图表
plt.savefig("Income_Spent.png")
plt.show()


plt.figure()
# 绘制小提琴图，显示每个集群的 spending 特征
pl = sns.swarmplot(x=df["Clusters"], y=df["Spent"], color="#CBEDDD", alpha=0.5)
# 绘制箱线图，显示每个集群的 spending 特征
pl = sns.boxenplot(x=df["Clusters"], y=df["Spent"])
# 显示图表
plt.savefig("Spent.png")
plt.show()

# 计算每个客户接受活动总数
df["Total_Promos"] = df["AcceptedCmp1"] + df["AcceptedCmp2"] + df["AcceptedCmp3"] + df["AcceptedCmp4"] + df[
    "AcceptedCmp5"]

# 绘制接受活动总数统计图
plt.figure()
pl = sns.countplot(x=df["Total_Promos"], hue=df["Clusters"])
pl.set_title("Count Of Promotion Accepted")
pl.set_xlabel("Number Of Total Accepted Promotions")
plt.savefig("Number Of Total Accepted Promotions")
plt.show()


# 绘制箱形图，比较不同聚类的购买数量
plt.figure()
pl = sns.boxenplot(y=df["NumDealsPurchases"], x=df["Clusters"])
pl.set_title("Number of Deals Purchased")
plt.savefig("Number of Deals Purchased")
plt.show()


"""小批量K-均值Mini-Batch K-Means是K-Means的修改版本，它使用小批量样本而不是整个数据集来更新聚类质心，这可以使其对大型数据集更快，并且可能对统计噪声更具鲁棒性。它是通过MiniBatchKMeans
类实现的，要调整的主要配置是将“n_clusters”超参数设置为数据中估计的集群数量。 """
# 导入sklearn.cluster中的MiniBatchKMeans
from sklearn.cluster import MiniBatchKMeans

# 创建一个MiniBatchKMeans实例，设置聚类数为4
MP = MiniBatchKMeans(n_clusters=4)

# 使用MiniBatchKMeans实例对PCA_df进行聚类，并将聚类结果赋值给MP_df
MP_df = MP.fit_predict(PCA_df)
PCA_df["Clusters"] = MP_df

# 将聚类结果赋值给df
df["Clusters"]= MP_df

# 绘制3D散点图，x,y,z为数据，s为点的大小，c为点的颜色，marker为点的形状，cmap为点的颜色映射
fig = plt.figure(figsize=(10,8))
ax = plt.subplot(111, projection='3d', label="bla")
ax.scatter(x, y, z, s=40, c=PCA_df["Clusters"], marker='o', cmap = 'viridis' )
ax.set_title("The Plot Of The Clusters")
plt.savefig("The Plot Of The Clusters.png")
plt.show()



pl = sns.countplot(x=df["Clusters"])
pl.set_title("Distribution Of The Clusters")
plt.savefig("Distribution Of The Clusters.png")
plt.show()
